home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_12_08 / weber / faxscale.c < prev    next >
C/C++ Source or Header  |  1994-06-11  |  7KB  |  176 lines

  1. /***************************************************************
  2.  * file: FAXSCALE.C
  3.  * purpose: Minimalist scaler.  Scales images over a range of
  4.  *  3% to 3200% with a worst case precision of 1/32.  This code
  5.  *  was designed to minimize data, stack and code requirements
  6.  *  while being reasonably fast and accurate.  Since the intended
  7.  *  use is in fax machine, the scaled lines are clipped or white
  8.  *  filled to FAX_WIDTH bytes.  Refer to the function headers for
  9.  *  more detailed information.  Image lines follow the usual
  10.  *  monochromatic format of 1 being black, 0 being white and
  11.  *  bit 7 of each byte being the leftmost pixel.  This code is
  12.  *  an algorithm test bench.  The production version is in
  13.  *  assembly.
  14.  * environment: ANSI C tested with Borland 4.0, Zortech 3.1 and
  15.  *      MSC 5.1
  16.  * contains:
  17.  *      init_fax_scale() - initializes the scaler
  18.  *      scale_fax_line() - scales a single image line
  19.  * history:
  20.  *  06-09-92 - initial code
  21.  *  04-04-94 - polished, reformatted, retested, condensed
  22.  **************************************************************/
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <assert.h>
  27.  
  28.  
  29. /* data types and defines */
  30.  
  31. typedef unsigned long ROTATOR;      /* rotator type sets scaling
  32.                                      * range and precision */
  33. #define PRECISION (4 * 8)           /* ANSI doesn't allow sizeof(ROTATOR)
  34.                                      * in preprocessor */
  35. #define SCALE_MAX (PRECISION * 100) /* upper limit of scaler in % */
  36. #define SCALE_MIN (100 / PRECISION) /* lower limit of scaler in % */
  37. #define FAX_WIDTH 216               /* hardwired byte width of a fax line */
  38.  
  39. /* rotate instruction, just a kludge until assembly */
  40. #define _ror(val) (val) = ((val) >> 1 | (val) << (PRECISION-1))
  41.  
  42.  
  43. /* ROMmable const data */
  44.             /* sequential increase in bits per byte: do not change
  45.              * without looking closely at init_rotator() */
  46. static const unsigned char pattern[] =
  47.     {0x00,0x10,0x44,0x94,0xaa,0xda,0xee,0xfe,0xff,0xff};
  48.  
  49.  
  50. /* RAM data */
  51. static ROTATOR x_rotator;           /* rotating horizontal pattern */
  52. static ROTATOR y_rotator;           /* rotating vertical pattern */
  53. static unsigned int source_width;   /* number of bytes in a source line */
  54. static unsigned char x_base;        /* n/8 basis for x_rotator */
  55. static unsigned char y_base;        /* n/8 basis for y_rotator */
  56.  
  57.  
  58. /* local functions */
  59. static int init_rotator(int scale,ROTATOR *rotator,unsigned char *base);
  60.  
  61.  
  62. /************************************************
  63.  * function: int init_fax_scale(int x_scale,int y_scale,unsigned int source_byte_width)
  64.  *  Validate the scaling ranges and initialize the scaler.  You
  65.  *  must call this function first before you can use the scaler.
  66.  * parameters: horizontal and vertical scaling in percent followed
  67.  *             by the byte width of a source line.
  68.  * returns: 1 if Ok or 0 if either scale is out of range
  69.  ************************************************/
  70. int init_fax_scale(int x_scale,int y_scale,unsigned int source_byte_width)
  71.     {
  72.     if (!init_rotator(x_scale,&x_rotator,&x_base))
  73.         return 0;           /* set up x_rotator */
  74.     if (!init_rotator(y_scale,&y_rotator,&y_base))
  75.         return 0;           /* set up y_rotator */
  76.     source_width = source_byte_width;   /* save width */
  77.     if (((long)source_width * (long)x_scale) / 100L > FAX_WIDTH)
  78.         source_width = FAX_WIDTH;       /* clip to fax line */
  79.     return 1;
  80.     }
  81.  
  82.  
  83. /************************************************
  84.  * function: static int init_rotator(int scale,ROTATOR *rotator,unsigned char *base)
  85.  *  local function calculates the rotator and basis.
  86.  * parameters: scale factor in percent, pointer to rotator,
  87.  *             pointer to basis.
  88.  * returns: 1 if Ok or 0 if scale is out of range
  89.  ************************************************/
  90. static int init_rotator(int scale,ROTATOR *rotator,unsigned char *base)
  91.     {
  92.     unsigned int index,mix,i;
  93.  
  94.     /* check scaling range */
  95.     if (scale < SCALE_MIN || scale > SCALE_MAX)
  96.         return 0;
  97.     /* set basis */
  98.     *base = scale / 100;
  99.     /* get index into pattern */
  100.     scale %= 100;
  101.     index = (scale * 8) / 100;
  102.     /* How we mix 2 consecutive patterns to achieve balance.
  103.      * Express it this way to handle round off. */
  104.     mix = pattern[((((scale * 8) % 100) + 4) * 8) / 100];
  105.     /* for each byte in the rotator, select an appropriate
  106.      * pattern byte based on the index and the mix */
  107.     *rotator = 0;
  108.     for (i = sizeof(ROTATOR) ; i > 0 ; i--)
  109.         {
  110.         *rotator <<= 8;
  111.         *rotator |= pattern[index + (mix & 0x01)];
  112.         mix >>= 1;
  113.         }
  114.     assert((*rotator + *base) != 0);
  115.     assert(*base <= PRECISION);
  116.     return 1;
  117.     }
  118.  
  119.  
  120. /************************************************
  121.  * function: int scale_fax_line(unsigned char *dest, unsigned char *src)
  122.  *  Scale the line from src to dest.  dest will always be FAX_WIDTH
  123.  *  wide even if it requires clipping or whiting out the tail.  The
  124.  *  return value indicates the number of times to repeat the line.
  125.  *  A 0 return means skip it.  This was done to keep buffer control in
  126.  *  the caller.  Call scale_fax_line() once for each source line.
  127.  * parameters: pointer to destination and source
  128.  * returns: number of times to repeat the line (0 to PRECISION)
  129.  ************************************************/
  130. int scale_fax_line(unsigned char *dest, unsigned char *src)
  131.     {
  132.     int y_repeat,x_repeat,i,bit;
  133.     unsigned int accum,byte;
  134.     unsigned char *start;
  135.     ROTATOR rotator;
  136.  
  137.     /* get line repeat value and rotate to next */
  138.     y_repeat = y_base + (y_rotator & 0x01);
  139.     _ror(y_rotator);
  140.     /* if anything to do */
  141.     if (y_repeat)
  142.         {
  143.         rotator = x_rotator;
  144.         for (i=source_width, accum=1, start=dest ; i > 0 ; i--, src++)
  145.             {       /* each byte in the source line */
  146.             for (bit=8, byte=*src ; bit > 0 ; bit--)
  147.                 {   /* for each bit in the byte */
  148.                 x_repeat = x_base + (rotator & 1);
  149.                 _ror(rotator);      /* get repeat count and rotate */
  150.                 while (x_repeat--)
  151.                     {               /* for each repeat */
  152.                     accum <<= 1;    /* copy bit into accumulator */
  153.                     accum += ((byte & 0x80) != 0);
  154.                     if (accum & 0x100)
  155.                         {           /* output a byte and reset sentinel */
  156.                         *dest++ = accum & 0xff;
  157.                         accum = 1;
  158.                         }
  159.                     }
  160.                 byte <<= 1;
  161.                 }
  162.             }
  163.         if (accum > 1)
  164.             {                       /* handle fragment */
  165.             while ((accum & 0x100) == 0)
  166.                 accum <<= 1;
  167.             *dest++ = accum & 0xff;
  168.             }
  169.         while (dest < start + FAX_WIDTH)
  170.             {                       /* white out tail */
  171.             *dest++ = 0;
  172.             }
  173.         }
  174.     return y_repeat;
  175.     }
  176.